package com.nightsoul.shiro.test.chapter12.credentials;

import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.util.ByteSource;

import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;

import java.util.concurrent.atomic.AtomicInteger;

public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher {

    private Cache<String, AtomicInteger> passwordRetryCache;

    public RetryLimitHashedCredentialsMatcher(CacheManager cacheManager) {
        passwordRetryCache = cacheManager.getCache("passwordRetryCache");
    }

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        String username = (String)token.getPrincipal();
        //retry count + 1
        AtomicInteger retryCount = passwordRetryCache.get(username);
        if(retryCount == null) {
            retryCount = new AtomicInteger(0);
            passwordRetryCache.put(username, retryCount);
        }
        if(retryCount.incrementAndGet() > 5) {
            //if retry count > 5 throw
            throw new ExcessiveAttemptsException();
        }
        
        if(token instanceof UsernamePasswordToken) {
        	UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        	char[] password = Hashing.md5().hashString(new String(usernamePasswordToken.getPassword()), Charsets.UTF_8).toString().toCharArray();
            usernamePasswordToken.setPassword(password);
        }
        
        boolean matches = super.doCredentialsMatch(token, info);
        if(matches) {
            //clear retry count
            passwordRetryCache.remove(username);
        }
        return matches;
    }
    
    @Override
	protected Object getCredentials(AuthenticationInfo info) {
		if(info instanceof SimpleAuthenticationInfo) {
			SimpleAuthenticationInfo simpleAuthenticationInfo = (SimpleAuthenticationInfo) info;
			ByteSource salt = simpleAuthenticationInfo.getCredentialsSalt();
			return super.hashProvidedCredentials(simpleAuthenticationInfo.getCredentials(), salt, getHashIterations());
		}
		return super.getCredentials(info);
	}
    
}
